// ball_loggerfunctorpayloads.h                                       -*-C++-*-

// ----------------------------------------------------------------------------
//                                   NOTICE
//
// This component is not up to date with current BDE coding standards, and
// should not be used as an example for new development.
// ----------------------------------------------------------------------------

#ifndef INCLUDED_BALL_LOGGERFUNCTORPAYLOADS
#define INCLUDED_BALL_LOGGERFUNCTORPAYLOADS

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a suite of logger manager singleton functor payloads.
//
//@CLASSES
//  ball::LoggerFunctorPayloads: namespace for logger manager functor payloads
//
//@SEE_ALSO: ball_loggermanagerconfiguration, ball_loggermanager
//
//@DESCRIPTION: This component provides a namespace,
// 'ball::LoggerFunctorPayloads', containing a suite of functions, each of
// which may be used as the function body "payload" of one of the various
// 'bsl::function' functors used as callbacks in the 'ball_loggermanager'
// component.  Each function provides a specific customization or convenience
// enhancement to the basic logger functionality.
//
// !WARNING!: Note that all functions defined in this component are intended
// for use with the logger manager singleton *only*, and not with any
// non-singleton instances of 'ball::LoggerManager'; in particular, a
// precondition of each of the functions is that the logger manager singleton
// must be initialized and not in the process of being shut down.
//
// The lone function defined in 'ball::LoggerFunctorPayloads' at this time,
// 'loadParentCategoryThresholdValues', has signature:
//..
//  (int *, int *, int *, int *, const char *, char)
//..
// The initial five types in this signature match the following 'typedef' from
// 'ball::LoggerManager' (and 'ball::LoggerManagerConfiguration'):
//..
//  typedef bsl::function<void(int *, int *, int *, int *, const char *)>
//                                              DefaultThresholdLevelsCallback;
//      // 'DefaultThresholdLevelsCallback' is the type of the functor that
//      // determines default threshold levels for categories added to the
//      // registry by the 'setCategory(const char *)' method.
//..
// The purpose of the trailing 'char' argument is discussed in the following
// section, the Usage example, and the 'loadParentCategoryThresholdValues'
// function-level documentation.
//
///Support for Hierarchical Category Names
///---------------------------------------
// The 'ball' logging toolkit does not explicitly support any structure in the
// registry of category names; each unique sequence of characters defines a
// unique category that is, from the logger's perspective, a "peer" to all
// other categories.  The toolkit does, however, provide several callback
// mechanisms that facilitate customized naming conventions.
//
// In particular, the 'ball::LoggerManager' singleton can be configured with a
// 'DefaultThresholdLevelsCallback' (see the 'typedef' definition above) that,
// if not null, is invoked to populate the four threshold levels whenever the
// user creates a category having the "default" thresholds.  This component
// provides the function 'loadParentCategoryThresholdValues' that can be used
// as the payload to 'DefaultThresholdLevelsCallback'.
// 'loadParentCategoryThresholdValues' populates its four category threshold
// level arguments from a specified "child" category name and a 'char'
// delimiter by searching the category registry for a name that is "the most
// proximate parent category", assuming a hierarchical naming convention that
// uses the delimiter character.  If such a parent category is found, the
// "child" category will receive the threshold levels of the parent.  If no
// such parent exists, the new category will receive the standard "default"
// thresholds that it would have gotten had the callback been null.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example: Basic Usage
/// - - - - - - - - - -
// The following code snippets illustrate how to use this component's
// 'loadParentCategoryThresholdValues' method to allow a newly-created "child"
// category to inherit the logging threshold levels from its most proximate
// parent category (if such a category already exists).  Note that the category
// "hierarchy" is by naming convention only, but that the callback makes it
// simple for the *user* to impose hierarchical meaning on names that are, from
// the *logger's* perspective, peers.  In this example, we will choose the dot
// character ('.') as the hierarchy delimiter; to the logger itself, '.' is not
// special.
//
// To keep this example transparent, we will create and inspect several
// categories within 'main' directly; some categories will be "declared" to be
// "parent" categories, and we will set the threshold levels explicitly, while
// other categories will act as "children", which is to say that they will
// obtain their threshold levels through the callback mechanism.  In a more
// realistic example, there would be no explicit distinction between "parent"
// and "child" categories, but rather as categories are dynamically
// administered by the user, newly created categories would pick up the changes
// made to existing parents.  As a practical matter, the beginning of the
// function 'main' constitute the "usage" to *install* the callback; the rest
// of this example merely illustrates the *consequences* of that.
//
// First, we load the logger manager 'configuration' with the desired "payload"
// function, 'ball::LoggerFunctorPayloads::loadParentCategoryThresholdValues',
// and use the trailing 'char' argument 'delimiter', set to the value '.',
// which will be bound into the functor and supplied back to the payload on
// each invocation.
//..
//  // myapp.cpp
//  int main()
//  {
//      using namespace bdlf::PlaceHolders;
//
//      ball::LoggerManagerConfiguration configuration;
//      char delimiter = '.';
//      configuration.setDefaultThresholdLevelsCallback(
//          bdlf::BindUtil::bind(
//             &ball::LoggerFunctorPayloads::loadParentCategoryThresholdValues,
//             _1,
//             _2,
//             _3,
//             _4,
//             _5,
//             delimiter));
//..
// Then, we initialize the logger manager, using the configuration defined
// above:
//..
//      ball::LoggerManagerScopedGuard guard(configuration);
//..
// The above code is all that the user needs to do to customize the logger to
// "inherit" thresholds from parents.  The rest of this example illustrates the
// consequences of having installed 'myCallback'.  For convenience in what
// follows, we define a reference, 'manager', to the singleton logger manager.
//..
//      ball::LoggerManager& manager = ball::LoggerManager::singleton();
//..
// We now create two "parent" categories named "EQUITY.MARKET" and
// "EQUITY.GRAPHICS", and give them arbitrary but distinct threshold levels.
// We also set the default levels to distinct values in order to be able to
// verify exactly where "child" levels have come from later on.
//..
//      manager.setDefaultThresholdLevels(128, 96, 64, 32);
//
//      manager.addCategory("EQUITY.MARKET", 127, 95, 63, 31);
//      manager.addCategory("EQUITY.GRAPHICS", 129, 97, 65, 33);
//..
// Note that the call to 'addCategory', which takes the four 'int' threshold
// arguments, does not invoke the callback at all, but rather -- assuming that
// the named category does not yet exist -- sets the thresholds to the
// specified values directly.
//
// We can use the logger manager interface to verify that the levels have been
// set.  First, we use the 'lookupCategory' method to obtain the two parent
// categories (here assigned 'p1' and 'p2').
//..
//      const ball::Category *p1 = manager.lookupCategory("EQUITY.MARKET");
//      const ball::Category *p2 = manager.lookupCategory("EQUITY.GRAPHICS");
//..
// Next, we can use the appropriate 'ball::Category' accessor methods to
// 'assert' the expected results.  Recall that the ordered sequence of levels
// is "Record", "Pass", "Trigger", and "TriggerAll".
//..
//      assert(127 == p1->recordLevel());
//      assert( 95 == p1->passLevel());
//      assert( 63 == p1->triggerLevel());
//      assert( 31 == p1->triggerAllLevel());
//
//      assert(129 == p2->recordLevel());
//      assert( 97 == p2->passLevel());
//      assert( 65 == p2->triggerLevel());
//      assert( 33 == p2->triggerAllLevel());
//..
// Now, we will add several "child" categories using the 'setCategory' method
// taking a single argument, the 'char*' category name.  This method uses the
// callback in determining the "default" threshold levels to use.  The six
// statements are numbered for subsequent discussion.
//..
//      manager.setCategory("EQUITY.MARKET.NYSE");                      // (1)
//      manager.setCategory("EQUITY.MARKET.NASDAQ");                    // (2)
//      manager.setCategory("EQUITY.GRAPHICS.MATH.FACTORIAL");          // (3)
//      manager.setCategory("EQUITY.GRAPHICS.MATH.ACKERMANN");          // (4)
//      manager.setCategory("EQUITY.GRAPHICS.MATH");                    // (5)
//      manager.setCategory("EQUITY");                                  // (6)
//..
// Note that all six calls to 'setCategory' will succeed in adding new
// categories to the registry.  Calls (1)-(5) will "find" their parent's names
// and "inherit" the parent's levels.  Call (6), however, will not find a
// parent category, and so will receive the default threshold levels, just as
// if there were no callback installed.
//
// Note also that, although in this "static" (i.e., unadministered) example
// there is no significance to the order in which the above categories are
// created, in general (e.g., when categories are being dynamically
// administered) the order of creation *does* matter.  If line (5) were
// executed before line (4) then the call on line (4) would find the
// "EQUITY.GRAPHICS.MATH" category as its "parent" and inherit those threshold
// levels.  If, before line (4) executed, the thresholds of
// "EQUITY.GRAPHICS.MATH" were changed, then "EQUITY.GRAPHICS.MATH.FACTORIAL"
// and "EQUITY.GRAPHICS.MATH.ACKERMANN" would have different threshold levels
// despite their equivalent standing in the category hierarchy.
//
// Let us now verify some of the 24 threshold levels that have been set by the
// above calls.  We will verify the results of lines (1), (3), and (6) above.
//..
//      const ball::Category *c1, *c3, *c6;
//
//      c1 =  manager.lookupCategory("EQUITY.MARKET.NYSE");
//      assert(127 == c1->recordLevel());
//      assert( 95 == c1->passLevel());
//      assert( 63 == c1->triggerLevel());
//      assert( 31 == c1->triggerAllLevel());
//
//      c3 =  manager.lookupCategory("EQUITY.GRAPHICS.MATH.FACTORIAL");
//      assert(129 == c3->recordLevel());
//      assert( 97 == c3->passLevel());
//      assert( 65 == c3->triggerLevel());
//      assert( 33 == c3->triggerAllLevel());
//
//      c6 =  manager.lookupCategory("EQUITY");
//      assert(128 == c6->recordLevel());
//      assert( 96 == c6->passLevel());
//      assert( 64 == c6->triggerLevel());
//      assert( 32 == c6->triggerAllLevel());
//
//      return 0;
//  }
//..

#include <balscm_version.h>

namespace BloombergLP {
namespace ball {

                    // ============================
                    // struct LoggerFunctorPayloads
                    // ============================

struct LoggerFunctorPayloads {
    // This 'struct' provides a namespace for a suite of utility functions,
    // each of which may be used as the function body for an appropriate
    // 'bsl::function' callback functor within 'ball_loggermanager'.
    //
    // !WARNING!: Note that all functions are intended for use with the logger
    // manager singleton *only*, and not with any non-singleton instances of
    // 'ball::LoggerManager'.

    // CLASS METHODS
    static
    void loadParentCategoryThresholdValues(int        *recordLevel,
                                           int        *passLevel,
                                           int        *triggerLevel,
                                           int        *triggerAllLevel,
                                           const char *categoryName,
                                           char        delimiter);
        // Load into the specified 'recordLevel', 'passLevel', 'triggerLevel',
        // and 'triggerAllLevel' the respective threshold levels of the
        // category in the registry of the (singleton) 'ball' logger manager
        // that is the most proximate parent category of the category having
        // the specified 'categoryName' among existing hierarchically named
        // categories in the registry, if such a parent category exists, or the
        // default thresholds otherwise; use the specified 'delimiter' to
        // define hierarchical category names.  The behavior is undefined
        // unless the logger manager singleton has been initialized and is not
        // in the process of being shut down.
};

}  // close package namespace
}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2015 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
